#ifndef PARSER_H
#define PARSER_H
#include <iostream>
#include <string>
using namespace std;

#include "rule.h"
#include "parsestream.h"
#include "primitives.h"
#include "action.h"

#include <iostream>
#include <string>
#include <stack>
#include <cmath>
#include <ctime>
#include "Expression.h"
#include "DerivationTree.h"
#include "AutoPointer.h"

struct ParseResult {
	int start;
	int end;
	bool result;
};

class GenericParser {
	public:
		GenericParser() { }
		
		GenericParser(const GenericParser&) { }

		template<typename T, typename U>
		ParseResult* parse(ParseStream* x, T & body, U & skipRule) {
			ParseResult *ris = new ParseResult;
			ris->start = x->getPosition();
			if (body.recognize(x)) {
				ris->end = x->getPosition();
				//cout << x->get() << endl;
				if (skipRule.recognize(x)) {//TODO what?
					x->setPosition(ris->end);
					ris->result = true;
				}
				else {
					x->setPosition(ris->start);
					ris->result = false;
				}
			}
			else {
				ris->result = false;
			}
			return ris;
		}
};


class LeonardParser : public GenericParser {
public:
	LeonardParser() : message_error(""), numberParameter(0) {
		numberInstruction.push(0);
		std::stack< AutoPointer<NodeTree> > firstNode;
		stack_operand.push(firstNode);
	}

	LeonardParser(const LeonardParser& copy) : GenericParser(copy), stack_operand(copy.stack_operand), message_error(copy.message_error), numberInstruction(copy.numberInstruction), numberParameter(copy.numberParameter) { }

	AutoPointer<NodeTree> top() const { return stack_operand.top().top(); }
	void pop() { stack_operand.top().pop(); }
	void push(AutoPointer<NodeTree> exp) { stack_operand.top().push(exp); }
	bool empty() const { return stack_operand.top().empty(); }
	int getSize() const { return stack_operand.top().size(); }
	/*void restore(const LeonardParser& toRestore) {
			stack_operand = toRestore.stack_operand;
			message_error = toRestore.message_error;
		}*/
	void save() {
		stack_operand.push(stack_operand.top());
	}
	void restore() {
		stack_operand.pop();
	}
	void clear() {
		std::stack< AutoPointer<NodeTree> > tmp = stack_operand.top();
		stack_operand.pop();
		stack_operand.pop();
		stack_operand.push(tmp);
	}

	void setNumberInstruction(int num) { numberInstruction.top() = num; }
	int getNumberInstruction() const { return numberInstruction.top(); }
	void addNumberInstruction() { ++numberInstruction.top(); }
	void pushNumberInstruction(int n) { numberInstruction.push(n); }
	void popNumberInstruction() { numberInstruction.pop(); }

	void setNumberParameter(int num) { numberParameter = num; }
	int getNumberParameter() const { return numberParameter; }
	void addNumberParameter() { ++numberParameter; }
private:
	std::stack< std::stack< AutoPointer<NodeTree> > > stack_operand;//TODO memory
	std::string message_error;
	std::stack<int> numberInstruction;
	int numberParameter;
};

#endif
